﻿using mozhi.smarterp.BasicData.Products.Repositories;
using mozhi.smarterp.BasicData.Products.Services;
using mozhi.smarterp.BasicData.TaxRates.Repository;
using mozhi.smarterp.BasicData.Units;
using Mozhi.Abp.Module.DataLinkage;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Volo.Abp;
using Volo.Abp.Application.Dtos;

namespace mozhi.smarterp.BasicData.Products
{
    public class ProductAppService : BasicDataAppService, IProductAppService
    {
        private IProductRepository _repository;
        private ProductManager _manager;
        private IUnitRepository _unitRepository;
        private IProductPurchaseSettingRepository _purchaseSettingRepository;
        private IProductInventoryRepository _inventoryRepository;
        private IProductInventorySettingRepository _inventorySettingRepository;
        private ITaxRateRepository _taxRateRepository;

        public ProductAppService(IProductRepository repository, ProductManager manager, IUnitRepository unitRepository,
            IProductPurchaseSettingRepository purchaseSettingRepository, IProductInventoryRepository inventoryRepository,
            IProductInventorySettingRepository inventorySettingRepository, IDataLinkageRepository dataLinkageRepository , ITaxRateRepository taxRateRepository) : base(dataLinkageRepository)
        {
            _repository = repository;
            _manager = manager;
            _unitRepository = unitRepository;
            _purchaseSettingRepository = purchaseSettingRepository;
            _inventoryRepository = inventoryRepository;
            _inventorySettingRepository = inventorySettingRepository;
            _taxRateRepository = taxRateRepository;
        }

        public async Task<PagedResultDto<ProductListDto>> GetListAsync(ProductResultRequestDto filter)
        {
            var products = await _repository.GetPagedListAsync(filter.Keyword , filter.Activated , filter.Types , 
                filter.Purchasable , filter.Saleable , filter.Producible , filter.Outsourceable , filter.Assetable, filter.SkipCount, filter.MaxResultCount, filter.Sorting, false);

            var count = await _repository.GetCountAsync(filter.Keyword, filter.Activated, filter.Types , filter.Purchasable, filter.Saleable, filter.Producible, filter.Outsourceable, filter.Assetable);

            var result = new PagedResultDto<ProductListDto>();

            result.Items = ObjectMapper.Map<List<Product>, List<ProductListDto>>(products);
            result.TotalCount = count;

            await LoadOtherInfoAsync((List<ProductListDto>)result.Items);

            return result;
        }

        public async Task<ProductDto> GetAsync(Guid id)
        {
            var product = await _repository.GetAsync(id);

            var result = ObjectMapper.Map<Product, ProductDto>(product);

            await LoadOtherInfoAsync(new List<ProductDto>() { result });

            return result;
        }

        public async Task<ProductDto> CreateAsync(ProductCreateDto input)
        {
            var product = await _manager.GetAsync(null , input.Code, input.Name, input.Type, input.BarCode , input.BasicUnitId, input.DefatultTaxRateId , input.DefaultSupplierId , input.Model , input.Activated);

            product.ChangeRestraint(input.Saleable, input.Purchasable, input.Producible, input.Outsourceable, input.Assetable);

            product = await _repository.InsertAsync(product);

            var result = ObjectMapper.Map<Product, ProductDto>(product);

            await LoadOtherInfoAsync(new List<ProductDto>() { result });

            return result;
        }

        public async Task<ProductDto> UpdateAsync(ProductUpdateDto input)
        {
            var product = await _manager.GetAsync(input.Id , input.Code , input.Name , input.Type , input.BarCode, input.BasicUnitId ,
                input.DefaultTaxRateId, input.DefaultSupplierId, input.Model, input.Activated);

            product.ChangeRestraint(input.Saleable, input.Purchasable, input.Producible, input.Outsourceable, input.Assetable);

            product = await _repository.UpdateAsync(product);

            var result = ObjectMapper.Map<Product, ProductDto>(product);

            await LoadOtherInfoAsync(new List<ProductDto>() { result });

            return result;
        }

        public async Task DeleteAsync(Guid id)
        {
            var product = await _repository.GetAsync(id);

            if (product == null)
                throw new UserFriendlyException($"产品：{id}不存在", "100000");

            var inventoryCount = await _inventoryRepository.GetCountAsync(id);

            if (inventoryCount > 0)
                throw new UserFriendlyException($"产品：{product.Code}存在库存", "100000");

            await _repository.DeleteAsync(id);

            await _purchaseSettingRepository.DeleteAsync(id);

            await _inventorySettingRepository.DeleteAsync(id);
        }

        #region
        private async Task LoadOtherInfoAsync(List<ProductListDto> products)
        {
            foreach (var product in products)
            {
                var unit = await _unitRepository.GetAsync(product.BasicUnitId);
                product.BasicUnitName = unit?.Name;

                var taxRate = product.DefaultTaxRateId.HasValue ? await _taxRateRepository.GetAsync(product.DefaultTaxRateId.Value) : null;

                product.DefaultTaxRateName = taxRate?.Name;
                product.DefaultTaxRateValue = taxRate?.Rate;

            }
        }

        private async Task LoadOtherInfoAsync(List<ProductDto> products)
        {
            foreach (var product in products)
            {
                var unit = await _unitRepository.GetAsync(product.BasicUnitId);

                product.BasicUnitName = unit?.Name;
            }
        }

        #endregion
    }
}
